/*
 * XDevice Library Basic Functionality Test
 * Tests core library interfaces directly
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <xdevice/xdevice.h>

#define TEST_DATA_DIR "/tmp/xdevice_test"
#define TEST_DEVICE_NAME "test-device"
#define TEST_DEVICE_SIZE (1024 * 1024)  // 1MB
#define TEST_BUFFER_SIZE 4096

static void print_test_header(const char* test_name) {
    printf("\n=== %s ===\n", test_name);
}

static void print_test_result(const char* test_name, int success) {
    if (success) {
        printf("✓ %s: PASSED\n", test_name);
    } else {
        printf("✗ %s: FAILED\n", test_name);
    }
}

static int create_test_directory(void) {
    struct stat st = {0};
    
    if (stat(TEST_DATA_DIR, &st) == -1) {
        if (mkdir(TEST_DATA_DIR, 0755) != 0) {
            perror("mkdir");
            return -1;
        }
    }
    return 0;
}

static int test_library_initialization(void) {
    print_test_header("Library Initialization Test");
    
    // Test 1: Initialize with valid parameters
    xdevice_context_t* ctx = xdevice_init(TEST_DATA_DIR, 1, 3);
    if (!ctx) {
        printf("Failed to initialize XDevice context\n");
        return 0;
    }
    
    printf("XDevice context initialized successfully\n");
    printf("Node ID: 1, Cluster size: 3, Data dir: %s\n", TEST_DATA_DIR);
    
    // Test 2: Get cluster info
    xdevice_cluster_info_t cluster_info;
    int result = xdevice_get_cluster_info(ctx, &cluster_info);
    if (result == XDEVICE_CORE_OK) {
        printf("Cluster info:\n");
        printf("  Node count: %d\n", cluster_info.node_count);
        printf("  Leader ID: %d\n", cluster_info.leader_id);
        printf("  Current term: %lu\n", cluster_info.current_term);
        printf("  Commit index: %lu\n", cluster_info.commit_index);
        printf("  Is healthy: %s\n", cluster_info.is_healthy ? "Yes" : "No");
    } else {
        printf("Warning: Failed to get cluster info (expected in single node test)\n");
    }
    
    // Cleanup
    xdevice_destroy(ctx);
    printf("Context destroyed successfully\n");
    
    return 1;
}

static int test_device_management(void) {
    print_test_header("Device Management Test");
    
    xdevice_context_t* ctx = xdevice_init(TEST_DATA_DIR, 1, 3);
    if (!ctx) {
        printf("Failed to initialize XDevice context\n");
        return 0;
    }
    
    // Test 1: Create device
    int result = xdevice_create_device(ctx, TEST_DEVICE_NAME, TEST_DEVICE_SIZE, XDEVICE_STORAGE_LOCAL);
    if (result != XDEVICE_CORE_OK) {
        printf("Failed to create device: %d\n", result);
        xdevice_destroy(ctx);
        return 0;
    }
    printf("Device '%s' created successfully (size: %d bytes)\n", TEST_DEVICE_NAME, TEST_DEVICE_SIZE);
    
    // Test 2: List devices
    char device_names[XDEVICE_MAX_DEVICES][XDEVICE_MAX_DEVICE_NAME];
    int device_count = xdevice_list_devices(ctx, device_names, XDEVICE_MAX_DEVICES);
    printf("Found %d devices:\n", device_count);
    for (int i = 0; i < device_count; i++) {
        printf("  - %s\n", device_names[i]);
    }
    
    // Test 3: Open device
    xdevice_device_t* device = xdevice_open_device(ctx, TEST_DEVICE_NAME);
    if (!device) {
        printf("Failed to open device '%s'\n", TEST_DEVICE_NAME);
        xdevice_destroy(ctx);
        return 0;
    }
    printf("Device '%s' opened successfully\n", TEST_DEVICE_NAME);
    
    // Test 4: Get device info
    xdevice_device_info_t device_info;
    result = xdevice_get_device_info(device, &device_info);
    if (result == XDEVICE_CORE_OK) {
        printf("Device info:\n");
        printf("  Name: %s\n", device_info.name);
        printf("  Size: %lu bytes\n", device_info.size);
        printf("  Block size: %u\n", device_info.block_size);
        printf("  Block count: %lu\n", device_info.block_count);
        printf("  State: %d\n", device_info.state);
        printf("  Storage type: %d\n", device_info.storage_type);
        printf("  Read-only: %s\n", device_info.readonly ? "Yes" : "No");
    } else {
        printf("Warning: Failed to get device info\n");
    }
    
    // Cleanup
    xdevice_close_device(device);
    printf("Device closed successfully\n");
    
    xdevice_destroy(ctx);
    
    return 1;
}

static int test_io_operations(void) {
    print_test_header("I/O Operations Test");
    
    xdevice_context_t* ctx = xdevice_init(TEST_DATA_DIR, 1, 3);
    if (!ctx) {
        printf("Failed to initialize XDevice context\n");
        return 0;
    }
    
    // Create and open device
    int result = xdevice_create_device(ctx, TEST_DEVICE_NAME, TEST_DEVICE_SIZE, XDEVICE_STORAGE_LOCAL);
    if (result != XDEVICE_CORE_OK && result != XDEVICE_CORE_ERROR_EXISTS) {
        printf("Failed to create device: %d\n", result);
        xdevice_destroy(ctx);
        return 0;
    }
    
    xdevice_device_t* device = xdevice_open_device(ctx, TEST_DEVICE_NAME);
    if (!device) {
        printf("Failed to open device\n");
        xdevice_destroy(ctx);
        return 0;
    }
    
    // Test 1: Write data
    char write_buffer[TEST_BUFFER_SIZE];
    memset(write_buffer, 0x42, sizeof(write_buffer));  // Fill with 'B'
    
    int64_t bytes_written = xdevice_write(device, 0, write_buffer, sizeof(write_buffer));
    if (bytes_written < 0) {
        printf("Write failed: %ld\n", bytes_written);
        xdevice_close_device(device);
        xdevice_destroy(ctx);
        return 0;
    }
    printf("Wrote %ld bytes to device\n", bytes_written);
    
    // Test 2: Sync data
    result = xdevice_sync(device);
    if (result != XDEVICE_CORE_OK) {
        printf("Sync failed: %d\n", result);
    } else {
        printf("Data synced successfully\n");
    }
    
    // Test 3: Read data back
    char read_buffer[TEST_BUFFER_SIZE];
    memset(read_buffer, 0, sizeof(read_buffer));
    
    int64_t bytes_read = xdevice_read(device, 0, read_buffer, sizeof(read_buffer));
    if (bytes_read < 0) {
        printf("Read failed: %ld\n", bytes_read);
        xdevice_close_device(device);
        xdevice_destroy(ctx);
        return 0;
    }
    printf("Read %ld bytes from device\n", bytes_read);
    
    // Test 4: Verify data
    int data_match = (memcmp(write_buffer, read_buffer, TEST_BUFFER_SIZE) == 0);
    if (data_match) {
        printf("Data verification: PASSED (write/read data matches)\n");
    } else {
        printf("Data verification: FAILED (write/read data mismatch)\n");
        // Show first few bytes for debugging
        printf("Written: %02x %02x %02x %02x...\n", 
               (unsigned char)write_buffer[0], (unsigned char)write_buffer[1], 
               (unsigned char)write_buffer[2], (unsigned char)write_buffer[3]);
        printf("Read:    %02x %02x %02x %02x...\n", 
               (unsigned char)read_buffer[0], (unsigned char)read_buffer[1], 
               (unsigned char)read_buffer[2], (unsigned char)read_buffer[3]);
    }
    
    // Test 5: Write at different offset
    uint64_t offset = TEST_BUFFER_SIZE;
    memset(write_buffer, 0x43, sizeof(write_buffer));  // Fill with 'C'
    
    bytes_written = xdevice_write(device, offset, write_buffer, sizeof(write_buffer));
    if (bytes_written > 0) {
        printf("Wrote %ld bytes at offset %lu\n", bytes_written, offset);
        
        // Read back and verify
        memset(read_buffer, 0, sizeof(read_buffer));
        bytes_read = xdevice_read(device, offset, read_buffer, sizeof(read_buffer));
        if (bytes_read > 0 && memcmp(write_buffer, read_buffer, TEST_BUFFER_SIZE) == 0) {
            printf("Offset write/read verification: PASSED\n");
        } else {
            printf("Offset write/read verification: FAILED\n");
        }
    }
    
    // Cleanup
    xdevice_close_device(device);
    xdevice_destroy(ctx);
    
    return data_match;
}

static int test_error_handling(void) {
    print_test_header("Error Handling Test");
    
    // Test 1: Invalid initialization
    xdevice_context_t* ctx = xdevice_init(NULL, 1, 3);
    if (ctx) {
        printf("Warning: Expected failure for NULL data_dir, but succeeded\n");
        xdevice_destroy(ctx);
    } else {
        printf("Correctly handled NULL data_dir parameter\n");
    }
    
    // Test 2: Valid initialization
    ctx = xdevice_init(TEST_DATA_DIR, 1, 3);
    if (!ctx) {
        printf("Failed to initialize for error testing\n");
        return 0;
    }
    
    // Test 3: Open non-existent device
    xdevice_device_t* device = xdevice_open_device(ctx, "non-existent-device");
    if (device) {
        printf("Warning: Expected failure for non-existent device, but succeeded\n");
        xdevice_close_device(device);
    } else {
        printf("Correctly handled non-existent device\n");
    }
    
    // Test 4: Create duplicate device
    int result1 = xdevice_create_device(ctx, "duplicate-test", TEST_DEVICE_SIZE, XDEVICE_STORAGE_LOCAL);
    int result2 = xdevice_create_device(ctx, "duplicate-test", TEST_DEVICE_SIZE, XDEVICE_STORAGE_LOCAL);
    
    if (result1 == XDEVICE_CORE_OK && result2 == XDEVICE_CORE_ERROR_EXISTS) {
        printf("Correctly handled duplicate device creation\n");
    } else {
        printf("Warning: Duplicate device handling may need attention (result1=%d, result2=%d)\n", result1, result2);
    }
    
    xdevice_destroy(ctx);
    
    return 1;
}

int main(void) {
    printf("XDevice Library Basic Functionality Test\n");
    printf("========================================\n");
    
    // Setup
    if (create_test_directory() != 0) {
        printf("Failed to create test directory\n");
        return 1;
    }
    
    int tests_passed = 0;
    int total_tests = 4;
    
    // Run tests
    if (test_library_initialization()) tests_passed++;
    print_test_result("Library Initialization", tests_passed == 1);
    
    if (test_device_management()) tests_passed++;
    print_test_result("Device Management", tests_passed == 2);
    
    if (test_io_operations()) tests_passed++;
    print_test_result("I/O Operations", tests_passed == 3);
    
    if (test_error_handling()) tests_passed++;
    print_test_result("Error Handling", tests_passed == 4);
    
    // Summary
    printf("\n========================================\n");
    printf("Test Summary: %d/%d tests passed\n", tests_passed, total_tests);
    
    if (tests_passed == total_tests) {
        printf("✓ All tests PASSED!\n");
        return 0;
    } else {
        printf("✗ Some tests FAILED!\n");
        return 1;
    }
}
